package src.ee.ioc.smaug.world.evolution;

import java.util.Random;

/**
 * Different kinds of mutation
 * @author Margarita Spichakova
 *
 */
public class Mutation {
    /**
     * Apply mutation according to parameter
     * @param individual  represented as boolean vector
     * @return mutated individual
     */
    public static boolean[] apply (boolean[] individual) {
        boolean[] newIndividual = new boolean[individual.length];
        switch (EnvDescription.MUTtype) {
        case MUTATION:
            newIndividual = simpleMutation(individual);
            break;
        case INVERSION:
            newIndividual = invertion(individual);
            break;
        }

        return newIndividual;
    }

    /**
     * Change/not change one bit according to mutation probability.
     * Without saving structure
     * @param individual represented as boolean vector
     * @return mutated individual
     */
    private static boolean[] simpleMutation(boolean[] individual) {
        Random rnd = new Random();
        boolean mutateB = false;
        double prob = rnd.nextInt(101) / 100;
        if (prob <= EnvDescription.mutationProb) {
            mutateB = true;
        }
        if (mutateB) {
            int mutationPoint = rnd.nextInt(individual.length - 1) + 1;
            if (individual[mutationPoint]) {
                individual[mutationPoint] = false;
            } else {
                individual[mutationPoint] = true;
            }

        }
        return individual;
    }

    /**
     * Change/not change order according to mutation probability.
     * Part of the chromosome is written wiseverse between two parts
     * Without saving structure
     * @param individual
     * @return inverted individual
     */
    private static boolean[] invertion(boolean[] individual) {
        Random rnd = new Random();
        boolean mutateB = false;

        boolean[] newIndividual = new boolean[individual.length];

        double prob = rnd.nextInt(101) / 100;

        if (prob <= EnvDescription.mutationProb) {
            mutateB = true;
        }
        if (mutateB) {

            int border1 = rnd.nextInt(individual.length - 1) + 1;
            int border2 = rnd.nextInt(individual.length - 1) + 1;

            while (border1 == border2) {
                border1 = rnd.nextInt(individual.length - 1) + 1;
                border2 = rnd.nextInt(individual.length - 1) + 1;
            }

            if (border1 > border2) {
                int buff = border2;
                border2 = border1;
                border1 = buff;
            }

            for (int i = 0; i < border1; i++) {
                newIndividual[i] = individual[i];
            }

            for (int i = border1; i < border2; i++) {
                newIndividual[i] = individual[border2 - 1 - i];
            }
            for (int i = border2; i < individual.length; i++) {
                newIndividual[i] = individual[i];
            }

        }
        return newIndividual;
    }

}
